home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / tcl / tkstep0.3b3 / tkstep0 / tkstep / tk3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-08  |  42.3 KB  |  1,489 lines

  1. /* 
  2.  * tk3d.c --
  3.  *
  4.  *    This module provides procedures to draw borders in
  5.  *    the three-dimensional Motif style.
  6.  *
  7.  * Copyright (c) 1990-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tk3d.c 1.52 96/02/15 18:51:30
  14.  */
  15. /*
  16.  * TkSTEP modifications Copyright by
  17.  * Alfredo K. Kojima
  18.  */
  19.  
  20. #include "tkPort.h"
  21. #include "tkInt.h"
  22.  
  23. /*
  24.  * One of the following data structures is allocated for
  25.  * each 3-D border currently in use.  Structures of this
  26.  * type are indexed by borderTable, so that a single
  27.  * structure can be shared for several uses.
  28.  */
  29.  
  30. typedef struct {
  31.     Screen *screen;        /* Screen on which the border will be used. */
  32.     Visual *visual;        /* Visual for all windows and pixmaps using
  33.                  * the border. */
  34.     int depth;            /* Number of bits per pixel of drawables where
  35.                  * the border will be used. */
  36.     Colormap colormap;        /* Colormap out of which pixels are
  37.                  * allocated. */
  38.     int refCount;        /* Number of different users of
  39.                  * this border.  */
  40.     XColor *bgColorPtr;        /* Background color (intensity
  41.                  * between lightColorPtr and
  42.                  * darkColorPtr). */
  43.     XColor *darkColorPtr;    /* Color for darker areas (must free when
  44.                  * deleting structure). NULL means shadows
  45.                  * haven't been allocated yet.*/
  46.     XColor *lightColorPtr;    /* Color used for lighter areas of border
  47.                  * (must free this when deleting structure).
  48.                  * NULL means shadows haven't been allocated
  49.                  * yet. */
  50.     Pixmap shadow;        /* Stipple pattern to use for drawing
  51.                  * shadows areas.  Used for displays with
  52.                  * <= 64 colors or where colormap has filled
  53.                  * up. */
  54.     GC bgGC;            /* Used (if necessary) to draw areas in
  55.                  * the background color. */
  56.     GC darkGC;            /* Used to draw darker parts of the
  57.                  * border. None means the shadow colors
  58.                  * haven't been allocated yet.*/
  59.     GC lightGC;            /* Used to draw lighter parts of
  60.                  * the border. None means the shadow colors
  61.                  * haven't been allocated yet. */
  62.     GC dark2GC;            /* Used to draw even darker part of shadows
  63.                  * (black)
  64.                  */
  65.     Tcl_HashEntry *hashPtr;    /* Entry in borderTable (needed in
  66.                  * order to delete structure). */
  67. } Border;
  68.  
  69. /*
  70.  * Hash table to map from a border's values (color, etc.) to a
  71.  * Border structure for those values.
  72.  */
  73.  
  74. static Tcl_HashTable borderTable;
  75. typedef struct {
  76.     Tk_Uid colorName;        /* Color for border. */
  77.     Colormap colormap;        /* Colormap used for allocating border
  78.                  * colors. */
  79.     Screen *screen;        /* Screen on which border will be drawn. */
  80. } BorderKey;
  81.  
  82. /*
  83.  * Maximum intensity for a color:
  84.  */
  85.  
  86. #define MAX_INTENSITY 65535
  87.  
  88.  
  89. static int initialized = 0;    /* 0 means static structures haven't
  90.                  * been initialized yet. */
  91.  
  92. /*
  93.  * Forward declarations for procedures defined in this file:
  94.  */
  95.  
  96. static void        BorderInit _ANSI_ARGS_((void));
  97. static void        GetShadows _ANSI_ARGS_((Border *borderPtr,
  98.                 Tk_Window tkwin));
  99. static int        Intersect _ANSI_ARGS_((XPoint *a1Ptr, XPoint *a2Ptr,
  100.                 XPoint *b1Ptr, XPoint *b2Ptr, XPoint *iPtr));
  101. static void        ShiftLine _ANSI_ARGS_((XPoint *p1Ptr, XPoint *p2Ptr,
  102.                 int distance, XPoint *p3Ptr));
  103.  
  104. /*
  105.  *--------------------------------------------------------------
  106.  *
  107.  * Tk_Get3DBorder --
  108.  *
  109.  *    Create a data structure for displaying a 3-D border.
  110.  *
  111.  * Results:
  112.  *    The return value is a token for a data structure
  113.  *    describing a 3-D border.  This token may be passed
  114.  *    to Tk_Draw3DRectangle and Tk_Free3DBorder.  If an
  115.  *    error prevented the border from being created then
  116.  *    NULL is returned and an error message will be left
  117.  *    in interp->result.
  118.  *
  119.  * Side effects:
  120.  *    Data structures, graphics contexts, etc. are allocated.
  121.  *    It is the caller's responsibility to eventually call
  122.  *    Tk_Free3DBorder to release the resources.
  123.  *
  124.  *--------------------------------------------------------------
  125.  */
  126.  
  127. Tk_3DBorder
  128. Tk_Get3DBorder(interp, tkwin, colorName)
  129.     Tcl_Interp *interp;        /* Place to store an error message. */
  130.     Tk_Window tkwin;        /* Token for window in which border will
  131.                  * be drawn. */
  132.     Tk_Uid colorName;        /* String giving name of color
  133.                  * for window background. */
  134. {
  135.     BorderKey key;
  136.     Tcl_HashEntry *hashPtr;
  137.     register Border *borderPtr;
  138.     int new;
  139.     XGCValues gcValues;
  140.  
  141.     if (!initialized) {
  142.     BorderInit();
  143.     }
  144.  
  145.     /*
  146.      * First, check to see if there's already a border that will work
  147.      * for this request.
  148.      */
  149.  
  150.     key.colorName = colorName;
  151.     key.colormap = Tk_Colormap(tkwin);
  152.     key.screen = Tk_Screen(tkwin);
  153.  
  154.     hashPtr = Tcl_CreateHashEntry(&borderTable, (char *) &key, &new);
  155.     if (!new) {
  156.     borderPtr = (Border *) Tcl_GetHashValue(hashPtr);
  157.     borderPtr->refCount++;
  158.     } else {
  159.  
  160.     /*
  161.      * No satisfactory border exists yet.  Initialize a new one.
  162.      */
  163.     
  164.     borderPtr = (Border *) ckalloc(sizeof(Border));
  165.     borderPtr->screen = Tk_Screen(tkwin);
  166.     borderPtr->visual = Tk_Visual(tkwin);
  167.     borderPtr->depth = Tk_Depth(tkwin);
  168.     borderPtr->colormap = key.colormap;
  169.     borderPtr->refCount = 1;
  170.     borderPtr->bgColorPtr = NULL;
  171.     borderPtr->darkColorPtr = NULL;
  172.     borderPtr->lightColorPtr = NULL;
  173.     borderPtr->shadow = None;
  174.     borderPtr->bgGC = None;
  175.     borderPtr->darkGC = None;
  176.     borderPtr->dark2GC = None;
  177.     borderPtr->lightGC = None;
  178.     borderPtr->hashPtr = hashPtr;
  179.     Tcl_SetHashValue(hashPtr, borderPtr);
  180.     
  181.     /*
  182.      * Create the information for displaying the background color,
  183.      * but delay the allocation of shadows until they are actually
  184.      * needed for drawing.
  185.      */
  186.     
  187.     borderPtr->bgColorPtr = Tk_GetColor(interp, tkwin, colorName);
  188.     if (borderPtr->bgColorPtr == NULL) {
  189.         goto error;
  190.     }
  191.     gcValues.foreground = borderPtr->bgColorPtr->pixel;
  192.     borderPtr->bgGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  193.     }
  194.     return (Tk_3DBorder) borderPtr;
  195.  
  196.     error:
  197.     Tk_Free3DBorder((Tk_3DBorder) borderPtr);
  198.     return NULL;
  199. }
  200.  
  201. /*
  202.  *--------------------------------------------------------------
  203.  *
  204.  * Tk_3DVerticalBevel --
  205.  *
  206.  *    This procedure draws a vertical bevel along one side of
  207.  *    an object.  The bevel is always rectangular in shape:
  208.  *            |||
  209.  *            |||
  210.  *            |||
  211.  *            |||
  212.  *            |||
  213.  *            |||
  214.  *    An appropriate shadow color is chosen for the bevel based
  215.  *    on the leftBevel and relief arguments.  Normally this
  216.  *    procedure is called first, then Tk_3DHorizontalBevel is
  217.  *    called next to draw neat corners.
  218.  *
  219.  * Results:
  220.  *    None.
  221.  *
  222.  * Side effects:
  223.  *    Graphics are drawn in drawable.
  224.  *
  225.  *--------------------------------------------------------------
  226.  */
  227.  
  228. void
  229. Tk_3DVerticalBevel(tkwin, drawable, border, x, y, width, height,
  230.     leftBevel, relief)
  231.     Tk_Window tkwin;        /* Window for which border was allocated. */
  232.     Drawable drawable;        /* X window or pixmap in which to draw. */
  233.     Tk_3DBorder border;        /* Token for border to draw. */
  234.     int x, y, width, height;    /* Area of vertical bevel. */
  235.     int leftBevel;        /* Non-zero means this bevel forms the
  236.                  * left side of the object;  0 means it
  237.                  * forms the right side. */
  238.     int relief;            /* Kind of bevel to draw.  For example,
  239.                  * TK_RELIEF_RAISED means interior of
  240.                  * object should appear higher than
  241.                  * exterior. */
  242. {
  243.     Border *borderPtr = (Border *) border;
  244.     GC left, right;
  245.     Display *display = Tk_Display(tkwin);
  246.     int half;
  247.     
  248.     
  249.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  250.     GetShadows(borderPtr, tkwin);
  251.     }
  252.     
  253.     if (relief == TK_RELIEF_RAISED) {
  254.     if (width > 1) {
  255.         if (leftBevel) {
  256.             left = borderPtr->lightGC;
  257.             right = borderPtr->bgGC;
  258.         } else {
  259.             left = borderPtr->darkGC;
  260.             right = borderPtr->dark2GC;
  261.         }
  262.         half = width/2;
  263.         XFillRectangle(display, drawable, left,
  264.          x, y, (unsigned) half, (unsigned) height);
  265.         XFillRectangle(display, drawable, right,
  266.         x+half, y, (unsigned) (width - half), (unsigned) height);
  267.     } else {
  268.         left = (leftBevel) ? borderPtr->lightGC : borderPtr->dark2GC;
  269.         XFillRectangle(display, drawable, left,
  270.          x, y, (unsigned) width, (unsigned) height);    
  271.      }
  272.     } else if (relief == TK_RELIEF_SUNKEN) {
  273.     if (width > 1) {
  274.         if (leftBevel) {
  275.             left = borderPtr->darkGC;
  276.             right = borderPtr->dark2GC;        
  277.         } else {
  278.             left = borderPtr->bgGC;
  279.            right = borderPtr->lightGC;
  280.         }
  281.         half = width/2;
  282.         XFillRectangle(display, drawable, left, 
  283.         x, y, (unsigned) half, (unsigned) height);
  284.         XFillRectangle(display, drawable, right, 
  285.         x + half, y, (unsigned) (width - half), (unsigned) height);
  286.         } else {
  287.         left = (leftBevel) ? borderPtr->dark2GC : borderPtr->lightGC;
  288.         XFillRectangle(display, drawable, left,
  289.          x, y, (unsigned) width, (unsigned) height);
  290.         }
  291.     } else if (relief == TK_RELIEF_RIDGE) {
  292.     left = borderPtr->lightGC;
  293.     right = borderPtr->darkGC;
  294.     ridgeGroove:
  295.     half = width/2;
  296.     if (!leftBevel && (width & 1)) {
  297.         half++;
  298.     }
  299.     XFillRectangle(display, drawable, left, x, y, (unsigned) half,
  300.         (unsigned) height);
  301.     XFillRectangle(display, drawable, right, x+half, y,
  302.         (unsigned) (width-half), (unsigned) height);
  303.     } else if (relief == TK_RELIEF_GROOVE) {
  304.     left = borderPtr->darkGC;
  305.     right = borderPtr->lightGC;
  306.     goto ridgeGroove;
  307.     } else if (relief == TK_RELIEF_FLAT) {
  308.     XFillRectangle(display, drawable, borderPtr->bgGC, x, y,
  309.         (unsigned) width, (unsigned) height);
  310.     }
  311. }
  312.  
  313. /*
  314.  *--------------------------------------------------------------
  315.  *
  316.  * Tk_3DHorizontalBevel --
  317.  *
  318.  *    This procedure draws a horizontal bevel along one side of
  319.  *    an object.  The bevel has mitered corners (depending on
  320.  *    leftIn and rightIn arguments).
  321.  *
  322.  * Results:
  323.  *    None.
  324.  *
  325.  * Side effects:
  326.  *    None.
  327.  *
  328.  *--------------------------------------------------------------
  329.  */
  330.  
  331. void
  332. Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, height,
  333.     leftIn, rightIn, topBevel, relief)
  334.     Tk_Window tkwin;        /* Window for which border was allocated. */
  335.     Drawable drawable;        /* X window or pixmap in which to draw. */
  336.     Tk_3DBorder border;        /* Token for border to draw. */
  337.     int x, y, width, height;    /* Bounding box of area of bevel.  Height
  338.                  * gives width of border. */
  339.     int leftIn, rightIn;    /* Describes whether the left and right
  340.                  * edges of the bevel angle in or out as
  341.                  * they go down.  For example, if "leftIn"
  342.                  * is true, the left side of the bevel
  343.                  * looks like this:
  344.                  *    ___________
  345.                  *     __________
  346.                  *      _________
  347.                  *       ________
  348.                  */
  349.     int topBevel;        /* Non-zero means this bevel forms the
  350.                  * top side of the object;  0 means it
  351.                  * forms the bottom side. */
  352.     int relief;            /* Kind of bevel to draw.  For example,
  353.                  * TK_RELIEF_RAISED means interior of
  354.                  * object should appear higher than
  355.                  * exterior. */
  356. {
  357.     Border *borderPtr = (Border *) border;
  358.     Display *display = Tk_Display(tkwin);
  359.     int bottom, halfway, x1, x2, x1Delta, x2Delta;
  360.     GC topGC = None, bottomGC = None;
  361.                 /* Initializations needed only to prevent
  362.                  * compiler warnings. */
  363.  
  364.     if ((borderPtr->lightGC == None) && (relief != TK_RELIEF_FLAT)) {
  365.     GetShadows(borderPtr, tkwin);
  366.     }
  367.  
  368.     /*
  369.      * Compute a GC for the top half of the bevel and a GC for the
  370.      * bottom half (they're the same in many cases).
  371.      */
  372.  
  373.     switch (relief) {
  374.     case TK_RELIEF_RAISED:
  375.         if (height==1) {
  376.             topGC = (topBevel) ? borderPtr->lightGC : borderPtr->dark2GC;
  377.         } else {
  378.         topGC = (topBevel) ? borderPtr->lightGC : borderPtr->darkGC;
  379.             bottomGC = (topBevel) ? borderPtr->bgGC : borderPtr->dark2GC;
  380.         }    
  381.         break;
  382.     case TK_RELIEF_SUNKEN:
  383.         if (height==1) {
  384.         topGC = (topBevel) ? borderPtr->dark2GC : borderPtr->lightGC;
  385.         } else {
  386.         topGC = (topBevel) ? borderPtr->darkGC : borderPtr->bgGC;
  387.             bottomGC = (topBevel) ? borderPtr->dark2GC : borderPtr->lightGC;
  388.         }
  389.         break;
  390.     case TK_RELIEF_RIDGE:
  391.         topGC = borderPtr->lightGC;
  392.         bottomGC = borderPtr->darkGC;
  393.         break;
  394.     case TK_RELIEF_GROOVE:
  395.         topGC = borderPtr->darkGC;
  396.         bottomGC = borderPtr->lightGC;
  397.         break;
  398.     case TK_RELIEF_FLAT:
  399.         topGC = bottomGC = borderPtr->bgGC;
  400.         break;
  401.     }
  402.  
  403.     /*
  404.      * Compute various other geometry-related stuff.
  405.      */
  406.  
  407.     x1 = x;
  408.     if (!leftIn) {
  409.     x1 += height-1;
  410.     }
  411.     x2 = x+width;
  412.     if (!rightIn) {
  413.     x2 -= height-1;
  414.     }
  415.     x1Delta = (leftIn) ? 1 : -1;
  416.     x2Delta = (rightIn) ? -1 : 1;
  417.     halfway = y + height/2;
  418.     if (!topBevel && (height & 1)) {
  419.     halfway++;
  420.     }
  421.     bottom = y + height;
  422.  
  423.     /* 
  424.      * if borderwidth is 1 just draw the line and get out
  425.      */
  426.     if (height==1) {
  427.     if (x1 < x2) {
  428.         XFillRectangle(display, drawable,
  429.         topGC, x1, y, (unsigned) (x2-x1-topBevel), (unsigned) 1);
  430.     }
  431.     } else {
  432.         /*
  433.          * Draw one line for each y-coordinate covered by the bevel.
  434.          */
  435.          for ( ; y < bottom; y++) {
  436.         /*
  437.          * In some weird cases (such as large border widths for skinny
  438.          * rectangles) x1 can be >= x2.  Don't draw the lines
  439.          * in these cases.
  440.          */
  441.  
  442.            if (x1 < x2) {
  443.         XFillRectangle(display, drawable,
  444.         (y < halfway) ? topGC : bottomGC, x1, y,
  445.         (unsigned) (x2-x1-topBevel), (unsigned) 1);
  446.         }
  447.         x1 += x1Delta;
  448.         x2 += x2Delta;
  449.     }
  450.     }
  451. }
  452.  
  453. /*
  454.  *--------------------------------------------------------------
  455.  *
  456.  * Tk_Draw3DRectangle --
  457.  *
  458.  *    Draw a 3-D border at a given place in a given window.
  459.  *
  460.  * Results:
  461.  *    None.
  462.  *
  463.  * Side effects:
  464.  *    A 3-D border will be drawn in the indicated drawable.
  465.  *    The outside edges of the border will be determined by x,
  466.  *    y, width, and height.  The inside edges of the border
  467.  *    will be determined by the borderWidth argument.
  468.  *
  469.  *--------------------------------------------------------------
  470.  */
  471.  
  472. void
  473. Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width, height,
  474.     borderWidth, relief)
  475.     Tk_Window tkwin;        /* Window for which border was allocated. */
  476.     Drawable drawable;        /* X window or pixmap in which to draw. */
  477.     Tk_3DBorder border;        /* Token for border to draw. */
  478.     int x, y, width, height;    /* Outside area of region in
  479.                  * which border will be drawn. */
  480.     int borderWidth;        /* Desired width for border, in
  481.                  * pixels. */
  482.     int relief;            /* Type of relief: TK_RELIEF_RAISED,
  483.                  * TK_RELIEF_SUNKEN, TK_RELIEF_GROOVE, etc. */
  484. {
  485.     if (width < 2*borderWidth) {
  486.     borderWidth = width/2;
  487.     }
  488.     if (height < 2*borderWidth) {
  489.     borderWidth = height/2;
  490.     }
  491.     Tk_3DVerticalBevel(tkwin, drawable, border, x, y, borderWidth, height,
  492.         1, relief);
  493.     Tk_3DVerticalBevel(tkwin, drawable, border, x+width-borderWidth, y,
  494.         borderWidth, height, 0, relief);
  495.     
  496.     Tk_3DHorizontalBevel(tkwin, drawable, border, x, y, width, borderWidth,
  497.         1, 1, 1, relief);
  498.     Tk_3DHorizontalBevel(tkwin, drawable, border, x, y+height-borderWidth,
  499.         width, borderWidth, 0, 0, 0, relief);    
  500. }
  501.  
  502. /*
  503.  *--------------------------------------------------------------
  504.  *
  505.  * Tk_NameOf3DBorder --
  506.  *
  507.  *    Given a border, return a textual string identifying the
  508.  *    border's color.
  509.  *
  510.  * Results:
  511.  *    The return value is the string that was used to create
  512.  *    the border.
  513.  *
  514.  * Side effects:
  515.  *    None.
  516.  *
  517.  *--------------------------------------------------------------
  518.  */
  519.  
  520. char *
  521. Tk_NameOf3DBorder(border)
  522.     Tk_3DBorder border;        /* Token for border. */
  523. {
  524.     Border *borderPtr = (Border *) border;
  525.  
  526.     return ((BorderKey *) borderPtr->hashPtr->key.words)->colorName;
  527. }
  528.  
  529. /*
  530.  *--------------------------------------------------------------------
  531.  *
  532.  * Tk_3DBorderColor --
  533.  *
  534.  *    Given a 3D border, return the X color used for the "flat"
  535.  *    surfaces.
  536.  *
  537.  * Results:
  538.  *    Returns the color used drawing flat surfaces with the border.
  539.  *
  540.  * Side effects:
  541.  *    None.
  542.  *
  543.  *--------------------------------------------------------------------
  544.  */
  545. XColor *
  546. Tk_3DBorderColor(border)
  547.     Tk_3DBorder border;        /* Border whose color is wanted. */
  548. {
  549.     return(((Border *) border)->bgColorPtr);
  550. }
  551.  
  552. /*
  553.  *--------------------------------------------------------------------
  554.  *
  555.  * Tk_3DBorderGC --
  556.  *
  557.  *    Given a 3D border, return the X color used for the "flat"
  558.  *    surfaces.
  559.  *
  560.  * Results:
  561.  *    Returns the color used drawing flat surfaces with the border.
  562.  *
  563.  * Side effects:
  564.  *    None.
  565.  *
  566.  *--------------------------------------------------------------------
  567.  */
  568. GC
  569. Tk_3DBorderGC(tkwin, border, which)
  570.     Tk_Window tkwin;        /* Window for which border was allocated. */
  571.     Tk_3DBorder border;        /* Border whose GC is wanted. */
  572.     int which;            /* Selects one of the border's 3 GC's:
  573.                  * TK_3D_FLAT_GC, TK_3D_LIGHT_GC, or
  574.                  * TK_3D_DARK_GC. */
  575. {
  576.     Border * borderPtr = (Border *) border;
  577.  
  578.     if ((borderPtr->lightGC == None) && (which != TK_3D_FLAT_GC)) {
  579.     GetShadows(borderPtr, tkwin);
  580.     }
  581.     if (which == TK_3D_FLAT_GC) {
  582.     return borderPtr->bgGC;
  583.     } else if (which == TK_3D_LIGHT_GC) {
  584.     return borderPtr->lightGC;
  585.     } else if (which == TK_3D_DARK_GC){
  586.     return borderPtr->darkGC;
  587.     } else if (which == TK_3D_DARK2_GC) {
  588.     return borderPtr->dark2GC;
  589.     }    
  590.     panic("bogus \"which\" value in Tk_3DBorderGC");
  591.  
  592.     /*
  593.      * The code below will never be executed, but it's needed to
  594.      * keep compilers happy.
  595.      */
  596.  
  597.     return (GC) None;
  598. }
  599.  
  600. /*
  601.  *--------------------------------------------------------------
  602.  *
  603.  * Tk_Free3DBorder --
  604.  *
  605.  *    This procedure is called when a 3D border is no longer
  606.  *    needed.  It frees the resources associated with the
  607.  *    border.  After this call, the caller should never again
  608.  *    use the "border" token.
  609.  *
  610.  * Results:
  611.  *    None.
  612.  *
  613.  * Side effects:
  614.  *    Resources are freed.
  615.  *
  616.  *--------------------------------------------------------------
  617.  */
  618.  
  619. void
  620. Tk_Free3DBorder(border)
  621.     Tk_3DBorder border;        /* Token for border to be released. */
  622. {
  623.     register Border *borderPtr = (Border *) border;
  624.     Display *display = DisplayOfScreen(borderPtr->screen);
  625.  
  626.     borderPtr->refCount--;
  627.     if (borderPtr->refCount == 0) {
  628.     if (borderPtr->bgColorPtr != NULL) {
  629.         Tk_FreeColor(borderPtr->bgColorPtr);
  630.     }
  631.     if (borderPtr->darkColorPtr != NULL) {
  632.         Tk_FreeColor(borderPtr->darkColorPtr);
  633.     }
  634.     if (borderPtr->lightColorPtr != NULL) {
  635.         Tk_FreeColor(borderPtr->lightColorPtr);
  636.     }
  637.     if (borderPtr->shadow != None) {
  638.         Tk_FreeBitmap(display, borderPtr->shadow);
  639.     }
  640.     if (borderPtr->bgGC != None) {
  641.         Tk_FreeGC(display, borderPtr->bgGC);
  642.     }
  643.     if (borderPtr->darkGC != None) {
  644.         Tk_FreeGC(display, borderPtr->darkGC);
  645.     }
  646.     if (borderPtr->lightGC != None) {
  647.         Tk_FreeGC(display, borderPtr->lightGC);
  648.     }
  649.     if (borderPtr->dark2GC != None) {
  650.         Tk_FreeGC(display, borderPtr->dark2GC);
  651.     }
  652.     Tcl_DeleteHashEntry(borderPtr->hashPtr);
  653.     ckfree((char *) borderPtr);
  654.     }
  655. }
  656.  
  657. /*
  658.  *----------------------------------------------------------------------
  659.  *
  660.  * Tk_SetBackgroundFromBorder --
  661.  *
  662.  *    Change the background of a window to one appropriate for a given
  663.  *    3-D border.
  664.  *
  665.  * Results:
  666.  *    None.
  667.  *
  668.  * Side effects:
  669.  *    Tkwin's background gets modified.
  670.  *
  671.  *----------------------------------------------------------------------
  672.  */
  673.  
  674. void
  675. Tk_SetBackgroundFromBorder(tkwin, border)
  676.     Tk_Window tkwin;        /* Window whose background is to be set. */
  677.     Tk_3DBorder border;        /* Token for border. */
  678. {
  679.     register Border *borderPtr = (Border *) border;
  680.  
  681.     Tk_SetWindowBackground(tkwin, borderPtr->bgColorPtr->pixel);
  682. }
  683.  
  684. /*
  685.  *----------------------------------------------------------------------
  686.  *
  687.  * Tk_GetRelief --
  688.  *
  689.  *    Parse a relief description and return the corresponding
  690.  *    relief value, or an error.
  691.  *
  692.  * Results:
  693.  *    A standard Tcl return value.  If all goes well then
  694.  *    *reliefPtr is filled in with one of the values
  695.  *    TK_RELIEF_RAISED, TK_RELIEF_FLAT, or TK_RELIEF_SUNKEN.
  696.  *
  697.  * Side effects:
  698.  *    None.
  699.  *
  700.  *----------------------------------------------------------------------
  701.  */
  702.  
  703. int
  704. Tk_GetRelief(interp, name, reliefPtr)
  705.     Tcl_Interp *interp;        /* For error messages. */
  706.     char *name;            /* Name of a relief type. */
  707.     int *reliefPtr;        /* Where to store converted relief. */
  708. {
  709.     char c;
  710.     size_t length;
  711.  
  712.     c = name[0];
  713.     length = strlen(name);
  714.     if ((c == 'f') && (strncmp(name, "flat", length) == 0)) {
  715.     *reliefPtr = TK_RELIEF_FLAT;
  716.     } else if ((c == 'g') && (strncmp(name, "groove", length) == 0)
  717.         && (length >= 2)) {
  718.         *reliefPtr = TK_RELIEF_GROOVE;
  719.     } else if ((c == 'r') && (strncmp(name, "raised", length) == 0)
  720.         && (length >= 2)) {
  721.     *reliefPtr = TK_RELIEF_RAISED;
  722.     } else if ((c == 'r') && (strncmp(name, "ridge", length) == 0)) {
  723.         *reliefPtr = TK_RELIEF_RIDGE;
  724.     } else if ((c == 's') && (strncmp(name, "sunken", length) == 0)) {
  725.     *reliefPtr = TK_RELIEF_SUNKEN;
  726.     } else {
  727.     sprintf(interp->result, "bad relief type \"%.50s\":  must be %s",
  728.         name, "flat, groove, raised, ridge, or sunken");
  729.     return TCL_ERROR;
  730.     }
  731.     return TCL_OK;
  732. }
  733.  
  734. /*
  735.  *--------------------------------------------------------------
  736.  *
  737.  * Tk_NameOfRelief --
  738.  *
  739.  *    Given a relief value, produce a string describing that
  740.  *    relief value.
  741.  *
  742.  * Results:
  743.  *    The return value is a static string that is equivalent
  744.  *    to relief.
  745.  *
  746.  * Side effects:
  747.  *    None.
  748.  *
  749.  *--------------------------------------------------------------
  750.  */
  751.  
  752. char *
  753. Tk_NameOfRelief(relief)
  754.     int relief;        /* One of TK_RELIEF_FLAT, TK_RELIEF_RAISED,
  755.              * or TK_RELIEF_SUNKEN. */
  756. {
  757.     if (relief == TK_RELIEF_FLAT) {
  758.     return "flat";
  759.     } else if (relief == TK_RELIEF_SUNKEN) {
  760.     return "sunken";
  761.     } else if (relief == TK_RELIEF_RAISED) {
  762.     return "raised";
  763.     } else if (relief == TK_RELIEF_GROOVE) {
  764.     return "groove";
  765.     } else if (relief == TK_RELIEF_RIDGE) {
  766.     return "ridge";
  767.     } else {
  768.     return "unknown relief";
  769.     }
  770. }
  771.  
  772. /*
  773.  *--------------------------------------------------------------
  774.  *
  775.  * Tk_Draw3DPolygon --
  776.  *
  777.  *    Draw a border with 3-D appearance around the edge of a
  778.  *    given polygon.
  779.  *
  780.  * Results:
  781.  *    None.
  782.  *
  783.  * Side effects:
  784.  *    Information is drawn in "drawable" in the form of a
  785.  *    3-D border borderWidth units width wide on the left
  786.  *    of the trajectory given by pointPtr and numPoints (or
  787.  *    -borderWidth units wide on the right side, if borderWidth
  788.  *    is negative).
  789.  *
  790.  *--------------------------------------------------------------
  791.  */
  792.  
  793. void
  794. Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  795.     borderWidth, leftRelief)
  796.     Tk_Window tkwin;        /* Window for which border was allocated. */
  797.     Drawable drawable;        /* X window or pixmap in which to draw. */
  798.     Tk_3DBorder border;        /* Token for border to draw. */
  799.     XPoint *pointPtr;        /* Array of points describing
  800.                  * polygon.  All points must be
  801.                  * absolute (CoordModeOrigin). */
  802.     int numPoints;        /* Number of points at *pointPtr. */
  803.     int borderWidth;        /* Width of border, measured in
  804.                  * pixels to the left of the polygon's
  805.                  * trajectory.   May be negative. */
  806.     int leftRelief;        /* TK_RELIEF_RAISED or
  807.                  * TK_RELIEF_SUNKEN: indicates how
  808.                  * stuff to left of trajectory looks
  809.                  * relative to stuff on right. */
  810. {
  811.     XPoint poly[4], b1, b2, newB1, newB2;
  812.     XPoint perp, c, shift1, shift2;    /* Used for handling parallel lines. */
  813.     register XPoint *p1Ptr, *p2Ptr;
  814.     Border *borderPtr = (Border *) border;
  815.     GC gc;
  816.     int i, lightOnLeft, dx, dy, parallel, pointsSeen;
  817.     Display *display = Tk_Display(tkwin);
  818.  
  819.     if (borderPtr->lightGC == None) {
  820.     GetShadows(borderPtr, tkwin);
  821.     }
  822.  
  823.     /*
  824.      * Handle grooves and ridges with recursive calls.
  825.      */
  826.  
  827.     if ((leftRelief == TK_RELIEF_GROOVE) || (leftRelief == TK_RELIEF_RIDGE)) {
  828.     int halfWidth;
  829.  
  830.     halfWidth = borderWidth/2;
  831.     Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  832.         halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_RAISED
  833.         : TK_RELIEF_SUNKEN);
  834.     Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  835.         -halfWidth, (leftRelief == TK_RELIEF_GROOVE) ? TK_RELIEF_SUNKEN
  836.         : TK_RELIEF_RAISED);
  837.     return;
  838.     }
  839.  
  840.     /*
  841.      * If the polygon is already closed, drop the last point from it
  842.      * (we'll close it automatically).
  843.      */
  844.  
  845.     p1Ptr = &pointPtr[numPoints-1];
  846.     p2Ptr = &pointPtr[0];
  847.     if ((p1Ptr->x == p2Ptr->x) && (p1Ptr->y == p2Ptr->y)) {
  848.     numPoints--;
  849.     }
  850.  
  851.     /*
  852.      * The loop below is executed once for each vertex in the polgon.
  853.      * At the beginning of each iteration things look like this:
  854.      *
  855.      *          poly[1]       /
  856.      *             *        /
  857.      *             |      /
  858.      *             b1   * poly[0] (pointPtr[i-1])
  859.      *             |    |
  860.      *             |    |
  861.      *             |    |
  862.      *             |    |
  863.      *             |    |
  864.      *             |    | *p1Ptr            *p2Ptr
  865.      *             b2   *--------------------*
  866.      *             |
  867.      *             |
  868.      *             x-------------------------
  869.      *
  870.      * The job of this iteration is to do the following:
  871.      * (a) Compute x (the border corner corresponding to
  872.      *     pointPtr[i]) and put it in poly[2].  As part of
  873.      *       this, compute a new b1 and b2 value for the next
  874.      *       side of the polygon.
  875.      * (b) Put pointPtr[i] into poly[3].
  876.      * (c) Draw the polygon given by poly[0..3].
  877.      * (d) Advance poly[0], poly[1], b1, and b2 for the
  878.      *     next side of the polygon.
  879.      */
  880.  
  881.     /*
  882.      * The above situation doesn't first come into existence until
  883.      * two points have been processed;  the first two points are
  884.      * used to "prime the pump", so some parts of the processing
  885.      * are ommitted for these points.  The variable "pointsSeen"
  886.      * keeps track of the priming process;  it has to be separate
  887.      * from i in order to be able to ignore duplicate points in the
  888.      * polygon.
  889.      */
  890.  
  891.     pointsSeen = 0;
  892.     for (i = -2, p1Ptr = &pointPtr[numPoints-2], p2Ptr = p1Ptr+1;
  893.         i < numPoints; i++, p1Ptr = p2Ptr, p2Ptr++) {
  894.     if ((i == -1) || (i == numPoints-1)) {
  895.         p2Ptr = pointPtr;
  896.     }
  897.     if ((p2Ptr->x == p1Ptr->x) && (p2Ptr->y == p1Ptr->y)) {
  898.         /*
  899.          * Ignore duplicate points (they'd cause core dumps in
  900.          * ShiftLine calls below).
  901.          */
  902.         continue;
  903.     }
  904.     ShiftLine(p1Ptr, p2Ptr, borderWidth, &newB1);
  905.     newB2.x = newB1.x + (p2Ptr->x - p1Ptr->x);
  906.     newB2.y = newB1.y + (p2Ptr->y - p1Ptr->y);
  907.     poly[3] = *p1Ptr;
  908.     parallel = 0;
  909.     if (pointsSeen >= 1) {
  910.         parallel = Intersect(&newB1, &newB2, &b1, &b2, &poly[2]);
  911.  
  912.         /*
  913.          * If two consecutive segments of the polygon are parallel,
  914.          * then things get more complex.  Consider the following
  915.          * diagram:
  916.          *
  917.          * poly[1]
  918.          *    *----b1-----------b2------a
  919.          *                                \
  920.          *                                  \
  921.          *         *---------*----------*    b
  922.          *        poly[0]  *p2Ptr   *p1Ptr  /
  923.          *                                /
  924.          *              --*--------*----c
  925.          *              newB1    newB2
  926.          *
  927.          * Instead of using x and *p1Ptr for poly[2] and poly[3], as
  928.          * in the original diagram, use a and b as above.  Then instead
  929.          * of using x and *p1Ptr for the new poly[0] and poly[1], use
  930.          * b and c as above.
  931.          *
  932.          * Do the computation in three stages:
  933.          * 1. Compute a point "perp" such that the line p1Ptr-perp
  934.          *    is perpendicular to p1Ptr-p2Ptr.
  935.          * 2. Compute the points a and c by intersecting the lines
  936.          *    b1-b2 and newB1-newB2 with p1Ptr-perp.
  937.          * 3. Compute b by shifting p1Ptr-perp to the right and
  938.          *    intersecting it with p1Ptr-p2Ptr.
  939.          */
  940.  
  941.         if (parallel) {
  942.         perp.x = p1Ptr->x + (p2Ptr->y - p1Ptr->y);
  943.         perp.y = p1Ptr->y - (p2Ptr->x - p1Ptr->x);
  944.         (void) Intersect(p1Ptr, &perp, &b1, &b2, &poly[2]);
  945.         (void) Intersect(p1Ptr, &perp, &newB1, &newB2, &c);
  946.         ShiftLine(p1Ptr, &perp, borderWidth, &shift1);
  947.         shift2.x = shift1.x + (perp.x - p1Ptr->x);
  948.         shift2.y = shift1.y + (perp.y - p1Ptr->y);
  949.         (void) Intersect(p1Ptr, p2Ptr, &shift1, &shift2, &poly[3]);
  950.         }
  951.     }
  952.     if (pointsSeen >= 2) {
  953.         dx = poly[3].x - poly[0].x;
  954.         dy = poly[3].y - poly[0].y;
  955.         if (dx > 0) {
  956.         lightOnLeft = (dy <= dx);
  957.         } else {
  958.         lightOnLeft = (dy < dx);
  959.         }
  960.         if (lightOnLeft ^ (leftRelief == TK_RELIEF_RAISED)) {
  961.         gc = borderPtr->lightGC;
  962.         } else {
  963.         gc = borderPtr->darkGC;
  964.         }
  965.         XFillPolygon(display, drawable, gc, poly, 4, Convex,
  966.             CoordModeOrigin);
  967.     }
  968.     b1.x = newB1.x;
  969.     b1.y = newB1.y;
  970.     b2.x = newB2.x;
  971.     b2.y = newB2.y;
  972.     poly[0].x = poly[3].x;
  973.     poly[0].y = poly[3].y;
  974.     if (parallel) {
  975.         poly[1].x = c.x;
  976.         poly[1].y = c.y;
  977.     } else if (pointsSeen >= 1) {
  978.         poly[1].x = poly[2].x;
  979.         poly[1].y = poly[2].y;
  980.     }
  981.     pointsSeen++;
  982.     }
  983. }
  984.  
  985. /*
  986.  *----------------------------------------------------------------------
  987.  *
  988.  * Tk_Fill3DRectangle --
  989.  *
  990.  *    Fill a rectangular area, supplying a 3D border if desired.
  991.  *
  992.  * Results:
  993.  *    None.
  994.  *
  995.  * Side effects:
  996.  *    Information gets drawn on the screen.
  997.  *
  998.  *----------------------------------------------------------------------
  999.  */
  1000.  
  1001. void
  1002. Tk_Fill3DRectangle(tkwin, drawable, border, x, y, width,
  1003.     height, borderWidth, relief)
  1004.     Tk_Window tkwin;        /* Window for which border was allocated. */
  1005.     Drawable drawable;        /* X window or pixmap in which to draw. */
  1006.     Tk_3DBorder border;        /* Token for border to draw. */
  1007.     int x, y, width, height;    /* Outside area of rectangular region. */
  1008.     int borderWidth;        /* Desired width for border, in
  1009.                  * pixels. Border will be *inside* region. */
  1010.     int relief;            /* Indicates 3D effect: TK_RELIEF_FLAT,
  1011.                  * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */
  1012. {
  1013.     register Border *borderPtr = (Border *) border;
  1014.  
  1015.     XFillRectangle(Tk_Display(tkwin), drawable, borderPtr->bgGC,
  1016.         x, y, (unsigned int) width, (unsigned int) height);
  1017.     if (relief != TK_RELIEF_FLAT) {
  1018.     Tk_Draw3DRectangle(tkwin, drawable, border, x, y, width,
  1019.         height, borderWidth, relief);
  1020.     }
  1021. }
  1022.  
  1023. /*
  1024.  *----------------------------------------------------------------------
  1025.  *
  1026.  * Tk_Fill3DPolygon --
  1027.  *
  1028.  *    Fill a polygonal area, supplying a 3D border if desired.
  1029.  *
  1030.  * Results:
  1031.  *    None.
  1032.  *
  1033.  * Side effects:
  1034.  *    Information gets drawn on the screen.
  1035.  *
  1036.  *----------------------------------------------------------------------
  1037.  */
  1038.  
  1039. void
  1040. Tk_Fill3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  1041.     borderWidth, leftRelief)
  1042.     Tk_Window tkwin;        /* Window for which border was allocated. */
  1043.     Drawable drawable;        /* X window or pixmap in which to draw. */
  1044.     Tk_3DBorder border;        /* Token for border to draw. */
  1045.     XPoint *pointPtr;        /* Array of points describing
  1046.                  * polygon.  All points must be
  1047.                  * absolute (CoordModeOrigin). */
  1048.     int numPoints;        /* Number of points at *pointPtr. */
  1049.     int borderWidth;        /* Width of border, measured in
  1050.                  * pixels to the left of the polygon's
  1051.                  * trajectory.   May be negative. */
  1052.     int leftRelief;            /* Indicates 3D effect of left side of
  1053.                  * trajectory relative to right:
  1054.                  * TK_RELIEF_FLAT, TK_RELIEF_RAISED,
  1055.                  * or TK_RELIEF_SUNKEN. */
  1056. {
  1057.     register Border *borderPtr = (Border *) border;
  1058.  
  1059.     XFillPolygon(Tk_Display(tkwin), drawable, borderPtr->bgGC,
  1060.         pointPtr, numPoints, Complex, CoordModeOrigin);
  1061.     if (leftRelief != TK_RELIEF_FLAT) {
  1062.     Tk_Draw3DPolygon(tkwin, drawable, border, pointPtr, numPoints,
  1063.         borderWidth, leftRelief);
  1064.     }
  1065. }
  1066.  
  1067. /*
  1068.  *--------------------------------------------------------------
  1069.  *
  1070.  * BorderInit --
  1071.  *
  1072.  *    Initialize the structures used for border management.
  1073.  *
  1074.  * Results:
  1075.  *    None.
  1076.  *
  1077.  * Side effects:
  1078.  *    Read the code.
  1079.  *
  1080.  *-------------------------------------------------------------
  1081.  */
  1082.  
  1083. static void
  1084. BorderInit()
  1085. {
  1086.     initialized = 1;
  1087.     Tcl_InitHashTable(&borderTable, sizeof(BorderKey)/sizeof(int));
  1088. }
  1089.  
  1090. /*
  1091.  *--------------------------------------------------------------
  1092.  *
  1093.  * ShiftLine --
  1094.  *
  1095.  *    Given two points on a line, compute a point on a
  1096.  *    new line that is parallel to the given line and
  1097.  *    a given distance away from it.
  1098.  *
  1099.  * Results:
  1100.  *    None.
  1101.  *
  1102.  * Side effects:
  1103.  *    None.
  1104.  *
  1105.  *--------------------------------------------------------------
  1106.  */
  1107.  
  1108. static void
  1109. ShiftLine(p1Ptr, p2Ptr, distance, p3Ptr)
  1110.     XPoint *p1Ptr;        /* First point on line. */
  1111.     XPoint *p2Ptr;        /* Second point on line. */
  1112.     int distance;        /* New line is to be this many
  1113.                  * units to the left of original
  1114.                  * line, when looking from p1 to
  1115.                  * p2.  May be negative. */
  1116.     XPoint *p3Ptr;        /* Store coords of point on new
  1117.                  * line here. */
  1118. {
  1119.     int dx, dy, dxNeg, dyNeg;
  1120.  
  1121.     /*
  1122.      * The table below is used for a quick approximation in
  1123.      * computing the new point.  An index into the table
  1124.      * is 128 times the slope of the original line (the slope
  1125.      * must always be between 0 and 1).  The value of the table
  1126.      * entry is 128 times the amount to displace the new line
  1127.      * in y for each unit of perpendicular distance.  In other
  1128.      * words, the table maps from the tangent of an angle to
  1129.      * the inverse of its cosine.  If the slope of the original
  1130.      * line is greater than 1, then the displacement is done in
  1131.      * x rather than in y.
  1132.      */
  1133.  
  1134.     static int shiftTable[129];
  1135.  
  1136.     /*
  1137.      * Initialize the table if this is the first time it is
  1138.      * used.
  1139.      */
  1140.  
  1141.     if (shiftTable[0] == 0) {
  1142.     int i;
  1143.     double tangent, cosine;
  1144.  
  1145.     for (i = 0; i <= 128; i++) {
  1146.         tangent = i/128.0;
  1147.         cosine = 128/cos(atan(tangent)) + .5;
  1148.         shiftTable[i] = cosine;
  1149.     }
  1150.     }
  1151.  
  1152.     *p3Ptr = *p1Ptr;
  1153.     dx = p2Ptr->x - p1Ptr->x;
  1154.     dy = p2Ptr->y - p1Ptr->y;
  1155.     if (dy < 0) {
  1156.     dyNeg = 1;
  1157.     dy = -dy;
  1158.     } else {
  1159.     dyNeg = 0;
  1160.     }
  1161.     if (dx < 0) {
  1162.     dxNeg = 1;
  1163.     dx = -dx;
  1164.     } else {
  1165.     dxNeg = 0;
  1166.     }
  1167.     if (dy <= dx) {
  1168.     dy = ((distance * shiftTable[(dy<<7)/dx]) + 64) >> 7;
  1169.     if (!dxNeg) {
  1170.         dy = -dy;
  1171.     }
  1172.     p3Ptr->y += dy;
  1173.     } else {
  1174.     dx = ((distance * shiftTable[(dx<<7)/dy]) + 64) >> 7;
  1175.     if (dyNeg) {
  1176.         dx = -dx;
  1177.     }
  1178.     p3Ptr->x += dx;
  1179.     }
  1180. }
  1181.  
  1182. /*
  1183.  *--------------------------------------------------------------
  1184.  *
  1185.  * Intersect --
  1186.  *
  1187.  *    Find the intersection point between two lines.
  1188.  *
  1189.  * Results:
  1190.  *    Under normal conditions 0 is returned and the point
  1191.  *    at *iPtr is filled in with the intersection between
  1192.  *    the two lines.  If the two lines are parallel, then
  1193.  *    -1 is returned and *iPtr isn't modified.
  1194.  *
  1195.  * Side effects:
  1196.  *    None.
  1197.  *
  1198.  *--------------------------------------------------------------
  1199.  */
  1200.  
  1201. static int
  1202. Intersect(a1Ptr, a2Ptr, b1Ptr, b2Ptr, iPtr)
  1203.     XPoint *a1Ptr;        /* First point of first line. */
  1204.     XPoint *a2Ptr;        /* Second point of first line. */
  1205.     XPoint *b1Ptr;        /* First point of second line. */
  1206.     XPoint *b2Ptr;        /* Second point of second line. */
  1207.     XPoint *iPtr;        /* Filled in with intersection point. */
  1208. {
  1209.     int dxadyb, dxbdya, dxadxb, dyadyb, p, q;
  1210.  
  1211.     /*
  1212.      * The code below is just a straightforward manipulation of two
  1213.      * equations of the form y = (x-x1)*(y2-y1)/(x2-x1) + y1 to solve
  1214.      * for the x-coordinate of intersection, then the y-coordinate.
  1215.      */
  1216.  
  1217.     dxadyb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->y - b1Ptr->y);
  1218.     dxbdya = (b2Ptr->x - b1Ptr->x)*(a2Ptr->y - a1Ptr->y);
  1219.     dxadxb = (a2Ptr->x - a1Ptr->x)*(b2Ptr->x - b1Ptr->x);
  1220.     dyadyb = (a2Ptr->y - a1Ptr->y)*(b2Ptr->y - b1Ptr->y);
  1221.  
  1222.     if (dxadyb == dxbdya) {
  1223.     return -1;
  1224.     }
  1225.     p = (a1Ptr->x*dxbdya - b1Ptr->x*dxadyb + (b1Ptr->y - a1Ptr->y)*dxadxb);
  1226.     q = dxbdya - dxadyb;
  1227.     if (q < 0) {
  1228.     p = -p;
  1229.     q = -q;
  1230.     }
  1231.     if (p < 0) {
  1232.     iPtr->x = - ((-p + q/2)/q);
  1233.     } else {
  1234.     iPtr->x = (p + q/2)/q;
  1235.     }
  1236.     p = (a1Ptr->y*dxadyb - b1Ptr->y*dxbdya + (b1Ptr->x - a1Ptr->x)*dyadyb);
  1237.     q = dxadyb - dxbdya;
  1238.     if (q < 0) {
  1239.     p = -p;
  1240.     q = -q;
  1241.     }
  1242.     if (p < 0) {
  1243.     iPtr->y = - ((-p + q/2)/q);
  1244.     } else {
  1245.     iPtr->y = (p + q/2)/q;
  1246.     }
  1247.     return 0;
  1248. }
  1249.  
  1250. /*
  1251.  *----------------------------------------------------------------------
  1252.  *
  1253.  * GetShadows --
  1254.  *
  1255.  *    This procedure computes the shadow colors for a 3-D border
  1256.  *    and fills in the corresponding fields of the Border structure.
  1257.  *    It's called lazily, so that the colors aren't allocated until
  1258.  *    something is actually drawn with them.  That way, if a border
  1259.  *    is only used for flat backgrounds the shadow colors will
  1260.  *    never be allocated.
  1261.  *
  1262.  * Results:
  1263.  *    None.
  1264.  *
  1265.  * Side effects:
  1266.  *    The lightGC and darkGC fields in borderPtr get filled in,
  1267.  *    if they weren't already.
  1268.  * 
  1269.  *
  1270.  *----------------------------------------------------------------------
  1271.  */
  1272.  
  1273. static void
  1274. GetShadows(borderPtr, tkwin)
  1275.     Border *borderPtr;        /* Information about border. */
  1276.     Tk_Window tkwin;        /* Window where border will be used for
  1277.                  * drawing. */
  1278. {
  1279.     XColor lightColor, darkColor;
  1280.     int stressed, tmp1, tmp2;
  1281.     XGCValues gcValues;
  1282.  
  1283.     if (borderPtr->lightGC != None) {
  1284.     return;
  1285.     }
  1286.     stressed = TkCmapStressed(tkwin, borderPtr->colormap);
  1287.  
  1288.     /*
  1289.      * First, handle the case of a color display with lots of colors.
  1290.      * The shadow colors get computed using whichever formula results
  1291.      * in the greatest change in color:
  1292.      * 1. Lighter shadow is half-way to white, darker shadow is half
  1293.      *    way to dark.
  1294.      * 2. Lighter shadow is 40% brighter than background, darker shadow
  1295.      *    is 40% darker than background.
  1296.      */
  1297.  
  1298.     if (!stressed && (Tk_Depth(tkwin) >= 6)) {
  1299.     /*
  1300.      * This is a color display with lots of colors.  For the dark
  1301.      * shadow, cut 40% from each of the background color components.
  1302.      * For the light shadow, boost each component by 40% or half-way
  1303.      * to white, whichever is greater (the first approach works
  1304.      * better for unsaturated colors, the second for saturated ones).
  1305.      */
  1306.     
  1307.     darkColor.red = (60 * (int) borderPtr->bgColorPtr->red)/100;
  1308.     darkColor.green = (60 * (int) borderPtr->bgColorPtr->green)/100;
  1309.     darkColor.blue = (60 * (int) borderPtr->bgColorPtr->blue)/100;
  1310.     
  1311.     borderPtr->darkColorPtr = Tk_GetColorByValue(tkwin, &darkColor);
  1312.     gcValues.foreground = borderPtr->darkColorPtr->pixel;
  1313.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  1314.  
  1315.  
  1316.     /*
  1317.      * dark2 color is always black 
  1318.      */
  1319.     gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  1320.     borderPtr->dark2GC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  1321.  
  1322.     /*
  1323.      * light color is always white     
  1324.      */
  1325.  
  1326.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  1327.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  1328.     return;
  1329.     }
  1330.  
  1331.     if (borderPtr->shadow == None) {
  1332.     borderPtr->shadow = Tk_GetBitmap((Tcl_Interp *) NULL, tkwin,
  1333.         Tk_GetUid("gray50"));
  1334.     if (borderPtr->shadow == None) {
  1335.         panic("GetShadows couldn't allocate bitmap for border");
  1336.     }
  1337.     }
  1338.     if (borderPtr->visual->map_entries > 2) {
  1339.     /*
  1340.      * This isn't a monochrome display, but the colormap either
  1341.      * ran out of entries or didn't have very many to begin with.
  1342.      * Generate the light shadows with a white stipple and the
  1343.      * dark shadows with a black stipple.
  1344.      */
  1345.  
  1346.     gcValues.foreground = borderPtr->bgColorPtr->pixel;
  1347.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  1348.     gcValues.stipple = borderPtr->shadow;
  1349.     gcValues.fill_style = FillOpaqueStippled;
  1350.     borderPtr->darkGC = Tk_GetGC(tkwin,
  1351.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  1352.     gcValues.background = WhitePixelOfScreen(borderPtr->screen);
  1353.     borderPtr->lightGC = Tk_GetGC(tkwin,
  1354.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  1355.     
  1356.     gcValues.foreground = gcValues.background;
  1357.     borderPtr->dark2GC = Tk_GetGC(tkwin,
  1358.         GCForeground|GCBackground, &gcValues);
  1359.     return;
  1360.     }
  1361.  
  1362.     /*
  1363.      * This is just a measly monochrome display, hardly even worth its
  1364.      * existence on this earth.  Make one shadow a 50% stipple and the
  1365.      * other the opposite of the background.
  1366.      */
  1367.  
  1368.     gcValues.foreground = WhitePixelOfScreen(borderPtr->screen);
  1369.     gcValues.background = BlackPixelOfScreen(borderPtr->screen);
  1370.     gcValues.stipple = borderPtr->shadow;
  1371.  
  1372.     gcValues.fill_style = FillOpaqueStippled;
  1373.     borderPtr->lightGC = Tk_GetGC(tkwin,
  1374.         GCForeground|GCBackground|GCStipple|GCFillStyle, &gcValues);
  1375.     if (borderPtr->bgColorPtr->pixel
  1376.         == WhitePixelOfScreen(borderPtr->screen)) {
  1377.     gcValues.foreground = BlackPixelOfScreen(borderPtr->screen);
  1378.     borderPtr->darkGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  1379.     } else {
  1380.     borderPtr->darkGC = borderPtr->lightGC;
  1381.     borderPtr->lightGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
  1382.     }
  1383.  
  1384.  
  1385.     gcValues.foreground = gcValues.background;
  1386.     borderPtr->dark2GC = Tk_GetGC(tkwin,
  1387.         GCForeground|GCBackground, &gcValues);
  1388. }
  1389.  
  1390.  
  1391.  
  1392. /*
  1393.  *---------------------------------------------------------------------- 
  1394.  * 
  1395.  * Draw3DCircle --
  1396.  *     Draws a beveled circle
  1397.  * 
  1398.  * TODO: Fix circle code
  1399.  *---------------------------------------------------------------------- 
  1400.  */
  1401. void Tk_Draw3DCircle(display, tkwin, d, x, y, wid, rad, relief, border)
  1402.     Display *display;
  1403.     Tk_Window tkwin;
  1404.     Drawable d;
  1405.     int x, y;                      /* position in d */
  1406.     int wid;                /* border width */
  1407.     int rad;
  1408.     int relief;
  1409.     Tk_3DBorder border;
  1410. {
  1411.     GC lightGC, darkGC, dark2GC, bgGC;
  1412.     int half, i;
  1413.     
  1414.     if (relief==TK_RELIEF_SUNKEN) {    
  1415.     lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
  1416.     darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
  1417.     dark2GC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK2_GC);
  1418.     bgGC = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC);
  1419.     } else {
  1420.     darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
  1421.     lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
  1422.     bgGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK2_GC);
  1423.     dark2GC = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC);
  1424.     }    
  1425.     half = wid/2;
  1426.     if (half>1) {
  1427.     XSetLineAttributes(display, darkGC, half, LineSolid, CapButt,
  1428.         JoinMiter);
  1429.     XSetLineAttributes(display, lightGC, half, LineSolid, CapButt,
  1430.         JoinMiter);
  1431.     XSetLineAttributes(display, dark2GC, half, LineSolid, CapButt,
  1432.         JoinMiter);
  1433.     XSetLineAttributes(display, bgGC, half, LineSolid, CapButt, 
  1434.         JoinMiter);
  1435.     } 
  1436.     /*
  1437.      * These coords are based on trial and error
  1438.      */
  1439.     XDrawArc(display, d, dark2GC, x, y, rad*2-half, rad*2-half, 
  1440.     60*64, 150*64);
  1441.     XDrawArc(display, d, darkGC, x, y, rad*2, rad*2, 55*64, 160*64);
  1442.     XDrawArc(display, d, lightGC, x, y, rad*2, rad*2, 35*64, -160*64);
  1443.     XDrawArc(display, d, dark2GC, x+half, y+half, rad*2-half, 
  1444.     rad*2-half, 60*64, 150*64);    
  1445.     XDrawArc(display, d, bgGC, x, y, rad*2-half, rad*2-half, 
  1446.     30*64, -150*64);
  1447.     if (half>1) {
  1448.     XSetLineAttributes(display, dark2GC, 0, LineSolid, CapButt,
  1449.         JoinMiter);
  1450.     XSetLineAttributes(display, lightGC, 0, LineSolid, CapButt,
  1451.         JoinMiter);
  1452.     XSetLineAttributes(display, darkGC, 0, LineSolid, CapButt,
  1453.         JoinMiter);
  1454.     XSetLineAttributes(display, bgGC, 0, LineSolid, CapButt,
  1455.         JoinMiter);
  1456.     }
  1457. }
  1458.  
  1459.  
  1460.  
  1461. /*
  1462.  *----------------------------------------------------------------------
  1463.  * 
  1464.  * DrawCheckMark --
  1465.  *     
  1466.  *     Draws a 3D check mark on the drawable
  1467.  * 
  1468.  *----------------------------------------------------------------------
  1469.  */
  1470. void Tk_DrawCheckMark(display, tkwin, d, x, y, border)
  1471.     Display *display;
  1472.     Tk_Window tkwin;
  1473.     Drawable d;
  1474.     int x, y;                      /* position in d */
  1475.     Tk_3DBorder border;
  1476. {
  1477.     GC lightGC, darkGC, dark2GC;
  1478.     
  1479.     lightGC = Tk_3DBorderGC(tkwin,border,TK_3D_LIGHT_GC);
  1480.     darkGC = Tk_3DBorderGC(tkwin,border,TK_3D_DARK_GC);
  1481.     dark2GC = Tk_3DBorderGC(tkwin,border,TK_3D_DARK2_GC);
  1482.     XDrawLine(display, d, dark2GC, x+1, y+3, x+1, y+6); 
  1483.     XDrawLine(display, d, lightGC, x, y+3, x, y+8);     
  1484.     XDrawLine(display, d, lightGC, x, y+8, x+8, y);
  1485.     XDrawLine(display, d, dark2GC, x, y+9, x+8, y+1);
  1486.     XDrawLine(display, d, darkGC, x+1, y+9, x+8, y+2);
  1487. }
  1488.  
  1489.